`timescale 1ns / 1ps
// ********************************************************************
//	FileName	: ltc2357_master.v
//	Author		：hpy
//	Email		：yuan_hp@qq.com
//	Date		：2020年07月22日
//	Description	：ltc2357 FPGA主机 cmos模式下 写数据+读数据
// --------------------------------------------------------------------

module ltc2357_master(
	input clk,    // fspi时钟 × 2 = fclk
	input rst_n,
	input busy,
	//input scko,
	input sdo0,
	input sdo1,
	input sdo2,
	input sdo3,
	output reg scki,
	output reg sdi,
	output csn, //片选信号
	//output cmosn, //传输方式选择
	output reg [23:0] ad_data0 , //转换的ch0 ad数据
	output reg [23:0] ad_data1 , //转换的ch1 ad数据
	output reg [23:0] ad_data2 , //转换的ch2 ad数据
	output reg [23:0] ad_data3 , //转换的ch3 ad数据
	output done
);

assign csn = 1'b0; 

//同步busy信号
reg busy_diff1,busy_diff2;
wire busy_n;
assign busy_n = ~busy_diff1 & busy_diff2;
always@(posedge clk )
begin
	if(!rst_n)begin
		busy_diff1 <= 1'b0;
		busy_diff2 <= 1'b0; 
	end
	else begin
		busy_diff1 <= busy;
		busy_diff2 <= busy_diff1;
	end
end

//发送数据到ltc芯片的FSM  使用格雷码
localparam S_IDEL = 2'b00;
localparam S_SEND_1 = 2'b01;
localparam S_SEND_2 = 2'b11;
localparam S_DONE = 2'b10;

assign done = (cst==S_IDEL) ? 1'b1 : 1'b0 ;
reg [1 :0 ] cst ,nst;
reg [4:0]scnt;

//状态转移
always@(posedge clk)
begin
	if(!rst_n)begin
		cst <= S_IDEL ;
	end
	else begin
		cst <= nst;
	end
end

//状态转移判断
always@(*)
begin
	nst = S_IDEL;
	case(cst)
		S_IDEL:begin
			nst = busy_n ? S_SEND_1 : S_IDEL;
		end
		S_SEND_1:begin
			nst =  (scnt < 32'd24 ) ? S_SEND_2 : S_DONE;
		end
		S_SEND_2:begin
			nst =  (scnt < 32'd24 ) ? S_SEND_1 : S_DONE;
		end
		S_DONE:begin
			nst = S_IDEL;
		end
		default : nst = S_IDEL ; 
	endcase
end
//使用内部参考 输出设置及其测量范围
localparam RANG_1 = 24'hFFF000;  // -10.24 ~ +10.24v   111
localparam RANG_2 = 24'hDB6000;  // -10 ~ +10v         110
localparam RANG_3 = 24'hB6D000;  // 0 ~ +10.24v        101
localparam RANG_4 = 24'h924000;  // 0 ~ +10v           100
localparam RANG_5 = 24'h6DB000;  // -5.12 ~ +5.12V     011
localparam RANG_6 = 24'h492000;  // -5 ~ +5V           010
localparam RANG_7 = 24'h249000;  // 0 ~ +5.12V         001
localparam ZERO   = 24'h000000;  //通道不使能，AD输出全为0 

reg [23:0] send_data;
always@(posedge clk)
begin
	if(!rst_n)begin
		sdi <= 0;
		scki <= 1;
		scnt <= 0;
		send_data <= RANG_1;
	end
	else begin
		if( nst == S_IDEL)begin
			sdi <= 0;
			scki <= 1; 
			scnt <= 0;
			send_data <= RANG_1;
		end
		else if( nst == S_SEND_1 )begin
			if( scnt < 32'd24 )begin
				scki <= 1'b0;
				sdi <= send_data[23];
				send_data <= send_data << 1;
			end
			else begin
				scki <= 1'b0;
				sdi <= 1'b0;
			end
		end
		else if( nst == S_SEND_2 )begin
			if(scnt < 32'd24 )begin
				scki <= 1'b1;
				scnt <= scnt + 1;
			end
			else begin
				scki <= 1'b0;
			end
		end
		else begin
			scki <= 1'b1;
			sdi <= 1'b0;
		end
	end
end

//+++++++++++++++ AD数据串转并 ++++++++++++
//模拟接收LTC2357数据
//reg [23:0]ad_data0;
reg [24:0]rec_r0 , rec_r1 , rec_r2 ,rec_r3 ; 
//为了使用时钟下降沿来读取数据，设计中必须保证时钟在
//空闲的时候，处于高电平，。在使用时钟下降沿读取数据时，将会
//多移位一次，因此获取24位的数据，我们要薄脆25位数据，在刷新
//转换的数据时我们取临时ad数据存储的高24位
always@(negedge scki or posedge busy)
begin
	if(busy)begin
		ad_data0 <= rec_r0[23:0];
		ad_data1 <= rec_r1[23:0];
		ad_data2 <= rec_r2[23:0];
		ad_data3 <= rec_r3[23:0];
	end
	else begin 
		rec_r0 <= {rec_r0[23:0],sdo0};
		rec_r1 <= {rec_r1[23:0],sdo1};
		rec_r2 <= {rec_r2[23:0],sdo2};
		rec_r3 <= {rec_r3[23:0],sdo3};
	end
end


endmodule 

